import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;

import org.springframework.data.domain.Persistable;

import cn.seqdata.jpa.JpaAuditableObject;
import cn.seqdata.jpa.JpaGeneratedObject;
import cn.seqdata.jpa.JpaType;

public class JavaCoder {
	public static final String WORKSPACE = "C:/Users/jrxian/Workspaces";

	public Class<?> jpaIdResult(Class<?> clazz) throws Exception {
		if (Persistable.class.isAssignableFrom(clazz)) {
			return clazz.getMethod("getId").getReturnType();
		} else {
			return null;
		}
	}

	public void jpaRepository(String cxfProject, String pkgsPrefix, Class<?> clazz, Class<?> idClazz)
	    throws IOException {
		File dir = new File(WORKSPACE + '/' + cxfProject + "/src/main/java");
		File file = new File(dir, pkgsPrefix.replace('.', '/') + "/repos/" + clazz.getSimpleName() + "Repos.java");
		PrintWriter writer = new PrintWriter(file, "utf-8");

		writer.format("package %s.repos;\r\n", pkgsPrefix);
		writer.format("import org.springframework.data.jpa.repository.JpaRepository;\r\n");
		writer.format("\r\n");
		writer.format("import %s.jpa.%s;\r\n", pkgsPrefix, clazz.getSimpleName());
		if (!idClazz.getName().startsWith("java.lang.")) {
			writer.format("import %s.jpa.%s;\r\n", pkgsPrefix, idClazz.getSimpleName());
		}
		writer.format("\r\n");
		writer.format("public interface %sRepos extends JpaRepository<%s, %s> {}\r\n", clazz.getSimpleName(),
		    clazz.getSimpleName(), idClazz.getSimpleName());

		writer.close();
	}

	public void cxfInterface(String cxfProject, String pkgsPrefix, Class<?> clazz, Class<?> idClazz)
	    throws IOException {
		File dir = new File(WORKSPACE + '/' + cxfProject + "/src/main/java");
		File file = new File(dir, pkgsPrefix.replace('.', '/') + "/cxf/Jaxrs" + clazz.getSimpleName() + ".java");
		PrintWriter writer = new PrintWriter(file, "utf-8");

		writer.format("package %s.cxf;\r\n", pkgsPrefix);
		writer.format("import javax.ws.rs.PUT;\r\n");
		writer.format("import javax.ws.rs.Path;\r\n");
		writer.format("\r\n");

		if (JpaAuditableObject.class.isAssignableFrom(clazz)) {
			writer.format("import cn.seqdata.cxf.repos.JaxrsObjectRepository;\r\n");
		} else if (JpaType.class.isAssignableFrom(clazz)) {
			writer.format("import cn.seqdata.cxf.repos.JaxrsTypeRepository;\r\n");
		} else {
			writer.format("import cn.seqdata.cxf.repos.JaxrsRepository;\r\n");
			if (!idClazz.getName().startsWith("java.lang.")) {
				writer.format("import %s.jpa.%s;\r\n", pkgsPrefix, idClazz.getSimpleName());
			}
		}

		writer.format("import %s.jpa.%s;\r\n", pkgsPrefix, clazz.getSimpleName());
		writer.format("\r\n");

		writer.format("@Path(\"/%s\")\r\n", clazz.getSimpleName().toLowerCase());
		writer.format("public interface Jaxrs%s extends ", clazz.getSimpleName());
		if (JpaGeneratedObject.class.isAssignableFrom(clazz)) {
			writer.format("JaxrsObjectRepository<%s> {\r\n", clazz.getSimpleName());
		} else if (JpaType.class.isAssignableFrom(clazz)) {
			writer.format("JaxrsTypeRepository<%s> {\r\n", clazz.getSimpleName());
		} else {
			writer.format("JaxrsRepository<%s, %s> {\r\n", clazz.getSimpleName(), idClazz.getSimpleName());
		}

		writer.format("@PUT\r\n");
		writer.format("@Path(\"/\")\r\n");
		writer.format("@Override\r\n");
		writer.format("<S extends %s> S save(S entity);\r\n", clazz.getSimpleName());
		writer.format("}\r\n");

		writer.close();
	}

	public void cxfImplement(String cxfProject, String pkgsPrefix, Class<?> clazz, Class<?> idClazz)
	    throws IOException {
		File dir = new File(WORKSPACE + '/' + cxfProject + "/src/main/java");
		File file = new File(dir,
		    pkgsPrefix.replace('.', '/') + "/cxf/impl/Jaxrs" + clazz.getSimpleName() + "Impl.java");
		PrintWriter writer = new PrintWriter(file, "utf-8");

		writer.format("package %s.cxf.impl;\r\n", pkgsPrefix);
		writer.format("\r\n");
		writer.format("import org.springframework.beans.factory.annotation.Autowired;\r\n");
		writer.format("import org.springframework.data.jpa.repository.JpaRepository;\r\n");
		writer.format("import org.springframework.stereotype.Service;\r\n");
		writer.format("\r\n");
		writer.format("import %s.cxf.Jaxrs%s;\r\n", pkgsPrefix, clazz.getSimpleName());
		writer.format("import %s.jpa.%s;\r\n", pkgsPrefix, clazz.getSimpleName());
		writer.format("import %s.repos.%sRepos;\r\n", pkgsPrefix, clazz.getSimpleName());
		if (!idClazz.getName().startsWith("java.lang.")) {
			writer.format("import %s.jpa.%s;\r\n", pkgsPrefix, idClazz.getSimpleName());
		}
		writer.format("\r\n");
		writer.format("@Service\r\n");
		writer.format("public class Jaxrs%sImpl extends AbstractJaxrsRepository<%s, %s> implements Jaxrs%s {\r\n",
		    clazz.getSimpleName(), clazz.getSimpleName(), idClazz.getSimpleName(), clazz.getSimpleName());
		writer.format("@Autowired\r\n");
		writer.format("private %sRepos repository;\r\n", clazz.getSimpleName());

		writer.format("@Override\r\n");
		writer.format("public JpaRepository<%s, %s> getRepository() {\r\n", clazz.getSimpleName(),
		    idClazz.getSimpleName());
		writer.format("return repository;\r\n");
		writer.format("}\r\n");
		writer.format("}\r\n");

		writer.close();
	}

	public void doGenerate(String jpaProject, String cxfProject, String pkgsPrefix) throws Exception {
		File dir = new File(WORKSPACE + '/' + jpaProject + "/src/main/java");
		File jpaClassPath = new File(dir, pkgsPrefix.replace('.', '/') + "/jpa");

		for (String fileName : jpaClassPath.list()) {
			String className = fileName.substring(0, fileName.length() - 5);
			Class<?> clazz = Class.forName(pkgsPrefix + ".jpa." + className);
			Class<?> idClazz = jpaIdResult(clazz);

			if (null == idClazz)
				continue;

			System.out.format("%s implements Persistable<%s>\r\n", clazz.getSimpleName(), idClazz.getSimpleName());

			jpaRepository(jpaProject, pkgsPrefix, clazz, idClazz);
			cxfInterface(cxfProject, pkgsPrefix, clazz, idClazz);
			cxfImplement(cxfProject, pkgsPrefix, clazz, idClazz);
		}
	}

	public static void main(String[] args) throws Exception {
		String jpaProject = "spddr-pmos/spddr-pmos-jpa";
		String cxfProject = "spddr-pmos/spddr-pmos-cxf";
		String pkgsPrefix = "com.spddr.pmos";

		JavaCoder this$ = new JavaCoder();
		this$.doGenerate(jpaProject, cxfProject, pkgsPrefix);
	}
}
